package com.yan.design.java8.k8;

import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

/**
 * 8 反射
 *      编译时：通过javac命令，生成一个或多个.class文件
 *      运行时：生成的.class文件加载的内存中。（由JVM提供的类加载器完成）
 * @author shengren.yan
 * @create 2022-08-17
 */
public class Class1 {
    public static void main(String[] args) {

    }

    // 1.反射 获取Class实例
    public void test1() throws Exception{

        // 1、反射 获取Class实例
        // 方式 1.通过运行时的类的属性class
        Class<APOJO> a1 = APOJO.class;
        // 方式 2.通过运行的对象
        APOJO p = new APOJO();
        Class<? extends APOJO> s2 = p.getClass();
        // 方式 3.通过Class的静态方法forName()
        String p2 = "com.yan.design.java8.k8.APOJO";  // 全路径的包名 + 类名
        Class<?> aClass = Class.forName(p2);
        // 方式 4.通过类加载器
        ClassLoader classLoader = this.getClass().getClassLoader();
        Class<?> aClass1 = classLoader.loadClass(p2); // 全路径的包名 + 类名

        // 2 加载器 （有3个 引导力类加载器、扩展类加载器、系统类加载器）
        ClassLoader parent = classLoader.getParent(); // 得到父的加载器
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("com.yan.design.ja.xxx"); //获取资源
    }

    // 2.反射 获取属性、方法、构造器、内部类、注解、接口、父类。。。
    public void test2() throws Exception{
        Class<APOJO> a1 = APOJO.class;
        APOJO apojo = a1.newInstance();     // 创建对象
        Field[] fields = a1.getFields();    // 获取 所有public修饰的属性，包括父类的
        for (Field f:fields){
            // 获取每个属性的结构
            // 获取 修饰符
            String s = Modifier.toString(f.getModifiers());
            // 获取数据类型
            Class<?> type = f.getType();
            String name = type.getName();
        }
        Field[] fields2 = a1.getDeclaredFields(); // 获取 本类所有声明的属性，不包含父类
        Method[] methods = a1.getMethods();          // 获取 所有public修饰的方法，包括父类的
        for (Method f:methods){
            // 获取每个方法的结构
            // 获取 修饰符
            String s = Modifier.toString(f.getModifiers());
            // 获取数 返回值 数据类型
            Class<?> type = f.getReturnType();
            String name = type.getName();
            // 获取方法名
            String name1 = f.getName();
            // 获取参数列表
            Class<?>[] parameterTypes = f.getParameterTypes();
            // 获取注解
            Annotation[] annotation = f.getAnnotations();
            // 获取异常
            Class<?>[] exceptionTypes2 = f.getExceptionTypes();
        }
        Method[] methods2 = a1.getDeclaredMethods(); // 获取 本类所有声明的方法，不包含父类
        Constructor<?>[] c1 = a1.getConstructors();  // 获取 所有public修饰的构造器，包括父类的
        Constructor<?>[] c2 = a1.getDeclaredConstructors();  // 获取 本类所有声明的构造器，不包含父类

        // 获取父类
        Class<? super APOJO> superclass = a1.getSuperclass(); // 得到父类的Class
        // 获取带泛型的父类的类型
        Type type = a1.getGenericSuperclass(); // 得到 com.xxx.父类<java.long.String>
        // 获取带泛型的父类的类型的类型
        ParameterizedType type1 = (ParameterizedType) type;
        Type[] ts = type1.getActualTypeArguments(); // 得到多个类型的Class实例
        Class c = (Class) ts[0];
        String name = c.getName();        // 得到String类型

        // 获取接口
        Class<?>[] interfaces = a1.getInterfaces();
        // 获取内部类/获取私有的内部类
        Class<?>[] classes = a1.getClasses();
        Class<?>[] classes2 = a1.getDeclaredClasses();
        // 获取注解  注解的生命周期需要是RunTime
        Annotation[] annotations = a1.getAnnotations();
        for (Annotation a:annotations){
//            注解类 xx = (注解类) a;
//            xx.value(); // 注解默认值
        }
        // 获取包
        Package aPackage = a1.getPackage();

    }


    // 3.反射 操作对象
    public void test3() throws Exception{
        Class<APOJO> a1 = APOJO.class;
        APOJO apojo = a1.newInstance();
        Field name = a1.getField("name"); // 获取该对象的属性名， 参数：属性名
        // 设置属性值
        name.set(apojo,18);
        // 获取属性值
        Object o = name.get(apojo);
        //
        Field name1 = a1.getDeclaredField("name"); // 获取该对象的属性名，可以获取到 private修饰的
        name1.setAccessible(true); // 忽略权限
        name1.set(apojo,18);       // 私有的也可以设置

        // 方法
        Method getNames = a1.getMethod("getName"); // 获取该对象的方法， 参数：方法名
        // 执行这个方法 , 如果有返回值是Object
        Object invoke = getNames.invoke(apojo);
        // 获取该对象的方法， 参数：方法名,后面是可变参数
        Method getNames2 = a1.getMethod("setName",String.class,Integer.class,double.class, BigDecimal.class);
        getNames2.invoke(apojo,"ss",1,2.1,new BigDecimal(1));

        // 构造器
        Constructor<APOJO> constructor = a1.getConstructor(String.class, Integer.class);
        APOJO aa = constructor.newInstance("aa", 1); // 通过构造器获取对象

    }


}
